<?php

/**
  +------------------------------------------------------------------------------
 * Run Framework Redis操作类
  +------------------------------------------------------------------------------
 * @date    17-06
 * @author Jimmy Wang <1105235512@qq.com>
 * @version 1.0
  +------------------------------------------------------------------------------
 */
class RunRedis {

    public $name = "queue"; //队列默认名称
    public $q = null; //队列连接对象
    public $configFile = null; //配置文件
    public $prefix = ''; //前缀

    public function __construct() {//构造子
    }

    /**
     * 释放资源
     */
    public function __destruct() {
        $this->close();
        $this->q = null;
        $this->configFile = null;
        $this->name = null;
    }

    /**
     * 连接到队列
     */
    private function connect() {
        if ($this->q == null) {
            if (!file_exists($this->configFile)) {
                RunException::throwException("缓存配置文件：" . $this->configFile . "不存在!");
            }
            require($this->configFile);
            $this->q = new Redis();
            $this->q->connect($host, $port);
        }
    }

    /**
     * 关闭队列连接
     */
    private function close() {
        if ($this->q != null) {
            $this->q->close();
        }
    }

    /**
     * 数据入队
     */
    public function push($data) {
        $this->connect();
        $bool = $this->q->lPush($this->prefix . $this->name, serialize($data));
        return $bool;
    }

    /**
     * 数据出队返回名称为key的list中start至end之间的元素
     */
    public function getlist($key, $start = 0, $end = -1) {
        $this->connect();
        $data = $this->q->lrange($this->prefix . $key, $start, $end); //lGetRange($key,0,-1);
        return $data ? $data : '';
    }

    /**
     * 数据出队
     */
    public function pop() {
        $this->connect();
        $data = $this->q->rPop($this->prefix . $this->name);
        return $data ? unserialize($data) : '';
    }

    /**
     * 队列长度(队列中元素个数)
     */
    public function size() {
        $this->connect();
        return $this->q->llen($this->prefix . $this->name);
    }

    /**
     * 数据入队
     */
    public function lpush($key, $val) {
        $this->connect();
        $bool = $this->q->lPush($this->prefix . $key, serialize($val));
        return $bool;
    }

    /**
     * 数据出队
     */
    public function rpop($key) {
        $this->connect();
        $data = $this->q->rPop($this->prefix . $key);
        return $data ? unserialize($data) : '';
    }

    /**
     * 给数据库中名称为key的string赋予值value
     */
    public function set($key, $value, $expire = 86400) {
        $this->connect();
        return $this->q->setex($key, $expire, $value);
    }

    /**
     * 返回数据库中名称为key的string的value
     */
    public function get($key) {
        $this->connect();
        return $this->q->get($this->prefix . $key);
    }

    public function incr($key) {
        $this->connect();
        return $this->q->incr($this->prefix . $key);
    }

    /**
     * 名称为key的string增1操作 自增
     */
    public function keys($key) {
        $this->connect();
        $data = $this->q->keys($this->prefix . $key);
        return $data;
    }

    /**
     * 返回数据
     */
    public function hSort($key, $option) {
        $this->connect();
        $data = $this->q->SORT($this->prefix . $key, $option);
        return $data;
    }

    /**
     * 删除键名
     */
    public function del($key) {
        $this->connect();
        $bool = $this->q->del($this->prefix . $key);
        return $bool;
    }

    /**
     *  删除value相等的元素
     */
    public function lrem($key, $val, $count = 0) {
        $this->connect();
        $this->q->lrem($this->prefix . $key, $val, $count);
    }

    /*     * ***********redis HASH 操作命令**************** */

    /**
     * 向名称为hName的hash中添加元素hKey
     */
    public function hSet($hName, $hKey, $data) {
        $this->connect();
        $this->q->hSet($this->prefix . $hName, $hKey, serialize($data));
    }

    /**
     * 返回名称为hName的hash中hKey对应的value
     */
    public function hGet($hName, $hKey) {
        $this->connect();
        $data = $this->q->hget($this->prefix . $hName, $hKey);
        return $data ? unserialize($data) : '';
    }

    /**
     * 删除名称为hName的hash中hKey对应的value
     */
    public function hdel($hName, $hKey) {
        $this->connect();
        $data = $this->q->hdel($this->prefix . $hName, $hKey);
        return $data ? $data : '';
    }

    /**
     * 返回hash表元素个数
     * @param string $key 缓存key
     * @return int|bool
     */
    public function hLen($key) {
        $this->connect();
        return $this->q->hLen($key);
    }

    /**
     * 为hash表设定一个字段的值,如果字段存在，返回false
     * @param string $key 缓存key
     * @param string  $field 字段
     * @param string $value 值。
     * @return bool
     */
    public function hSetNx($key, $field, $value) {
        $this->connect();
        return $this->q->hSetNx($key, $field, $value);
    }

    /**
     * 为hash表多个字段设定值。
     * @param string $key
     * @param array $value
     * @return array|bool
     */
    public function hMset($key, $value) {
        $this->connect();
        if (!is_array($value))
            return false;
        return $this->q->hMset($key, $value);
    }

    /**
     * 为hash表设这累加，可以负数
     * @param string $key
     * @param int $field
     * @param string $value
     * @return bool
     */
    public function hIncrBy($key, $field, $value) {
        $this->connect();
        $value = intval($value);
        return $this->q->hIncrBy($key, $field, $value);
    }

    /**
     * 返回所有hash表的所有字段
     * @param string $key
     * @return array|bool
     */
    public function hKeys($key) {
        $this->connect();
        return $this->q->hKeys($key);
    }

    /**
     * 返回所有hash表的字段值，为一个索引数组
     * @param string $key
     * @return array|bool
     */
    public function hVals($key) {
        $this->connect();
        $data = $this->q->hVals($key);
        if(is_array($data)){
            foreach ($data as &$value) {
                $value = unserialize($value);
            }
            return $data;
        }
        
    }

    /**
     * 返回名称为hName的hash中所有键与对应的value
     */
    public function hGetAll($hName) {
        $this->connect();
        $data = $this->q->hGetAll($this->prefix . $hName);
        return $data;
    }

    /**
     * 返回名称为hName的hash中是否存在键名为hKey的域
     */
    public function hExists($hName, $hKey) {
        $this->connect();
        $data = $this->q->hExists($this->prefix . $hName, $hKey);
        return $data;
    }

    /*     * ***********redis字符串操作命令**************** */

    /**
     * 设置一个有过期时间的key
     * @param unknown $key
     * @param unknown $expire
     * @param unknown $value
     */
    public function setex($key, $value, $expire = 3600) {
        $this->connect();
        return $this->q->setex($key, $expire, $value);
    }

    /**
     * 设置一个key,如果key存在,不做任何操作.
     * @param unknown $key
     * @param unknown $value
     */
    public function setnx($key, $value) {
        $this->connect();
        return $this->q->setnx($key, $value);
    }

    /**
     * 批量设置key
     * @param unknown $arr
     */
    public function mset($arr) {
        $this->connect();
        return $this->q->mset($arr);
    }

    /*     * *******************有序集合操作******************** */

    /**
     * 给当前集合添加一个元素
     * 如果value已经存在，会更新order的值。
     * @param string $key
     * @param string $order 序号
     * @param string $value 值
     * @return bool
     */
    public function zAdd($key, $order, $value) {
        $this->connect();
        return $this->q->zAdd($key, $order, $value);
    }

    /**
     * 给$value成员的order值，增加$num,可以为负数
     * @param string $key
     * @param string $num 序号
     * @param string $value 值
     * @return 返回新的order
     */
    public function zinCry($key, $num, $value) {
        $this->connect();
        return $this->q->zinCry($key, $num, $value);
    }

    /**
     * 删除值为value的元素
     * @param string $key
     * @param stirng $value
     * @return bool
     */
    public function zRem($key, $value) {
        $this->connect();
        return $this->q->zRem($key, $value);
    }

    /**
     * 集合以order递增排列后，0表示第一个元素，-1表示最后一个元素
     * @param string $key
     * @param int $start
     * @param int $end
     * @return array|bool
     */
    public function zRange($key, $start = 0, $end = -1) {
        $this->connect();
        return $this->q->zRange($key, $start, $end);
    }

    /**
     * 集合以order递减排列后，0表示第一个元素，-1表示最后一个元素
     * @param string $key
     * @param int $start
     * @param int $end
     * @return array|bool
     */
    public function zRevRange($key, $start = 0, $end = -1) {
        $this->connect();
        return $this->q->zRevRange($key, $start, $end);
    }

    /**
     * 集合以order递增排列后，返回指定order之间的元素。
     * min和max可以是-inf和+inf　表示最大值，最小值 此处的值是order的最大值和最小值
     * @param string $key
     * @param int $start
     * @param int $end
     * @package array $option 参数
     *     withscores=>true，表示数组下标为Order值，默认返回索引数组
     *     limit=>array(0,1) 表示从0开始，取一条记录。
     * @return array|bool
     */
    public function zRangeByScore($key, $start = '-inf', $end = "+inf", $option = array()) {
        $this->connect();
        return $this->q->zRangeByScore($key, $start, $end, $option);
    }

    /**
     * 集合以order递减排列后，返回指定order之间的元素。
     * min和max可以是-inf和+inf　表示最大值，最小值 此处的值是order的最大值和最小值
     * @param string $key
     * @param int $start
     * @param int $end
     * @package array $option 参数
     *     withscores=>true，表示数组下标为Order值，默认返回索引数组
     *     limit=>array(0,1) 表示从0开始，取一条记录。
     * @return array|bool
     */
    public function zRevRangeByScore($key, $start = '-inf', $end = "+inf", $option = array()) {
        $this->connect();
        return $this->q->zRevRangeByScore($key, $start, $end, $option);
    }

    /**
     * 返回order值在start end之间的数量
     * @param unknown $key
     * @param unknown $start
     * @param unknown $end
     */
    public function zCount($key, $start = '-inf', $end = '+inf') {
        $this->connect();
        return $this->q->zCount($key, $start, $end);
    }

    /**
     * 返回值为value的order值
     * @param unknown $key
     * @param unknown $value
     */
    public function zScore($key, $value) {
        $this->connect();
        return $this->q->zScore($key, $value);
    }

    /**
     * 返回集合以score递增加排序后，指定成员的排序号，从0开始。
     * @param unknown $key
     * @param unknown $value
     */
    public function zRank($key, $value) {
        $this->connect();
        return $this->q->zRank($key, $value);
    }

    /**
     * 返回集合以score递增加排序后，指定成员的排序号，从0开始。
     * @param unknown $key
     * @param unknown $value
     */
    public function zRevRank($key, $value) {
        $this->connect();
        return $this->q->zRevRank($key, $value);
    }

    /**
     * 删除集合中，score值在start end之间的元素　包括start end
     * min和max可以是-inf和+inf　表示最大值，最小值
     * @param unknown $key
     * @param unknown $start
     * @param unknown $end
     * @return 删除成员的数量。
     */
    public function zRemRangeByScore($key, $start, $end) {
        $this->connect();
        return $this->q->zRemRangeByScore($key, $start, $end);
    }

    /**
     * 返回集合元素个数。
     * @param unknown $key
     */
    public function zCard($key) {
        $this->connect();
        return $this->q->zCard($key);
    }

    /*     * ***********redis　无序集合操作命令**************** */

    /**
     * 返回集合中所有元素
     * @param unknown $key
     */
    public function sMembers($key) {
        $this->connect();
        return $this->q->sMembers($key);
    }

    /**
     * 求2个集合的差集
     * @param unknown $key1
     * @param unknown $key2
     */
    public function sDiff($key1, $key2) {
        $this->connect();
        return $this->q->sDiff($key1, $key2);
    }

    /**
     * 添加集合。由于版本问题，扩展不支持批量添加。这里做了封装
     * @param unknown $key
     * @param string|array $value
     */
    public function sAdd($key, $value) {
        $this->connect();
        if (!is_array($value)) {
            $arr = array($value);
        } else {
            $arr = $value;
        }
        foreach ($arr as $row) {
            $this->q->sAdd($key, $row);
        }
    }

    /**
     * 返回无序集合的元素个数
     * @param unknown $key
     */
    public function scard($key) {
        $this->connect();
        return $this->q->scard($key);
    }

    /**
     * 从集合中删除一个元素
     * @param unknown $key
     * @param unknown $value
     */
    public function srem($key, $value) {
        $this->connect();
        return $this->q->srem($key, $value);
    }

    /*     * *******************事务的相关方法*********************** */

    /**
     * 监控key,就是一个或多个key添加一个乐观锁
     * 在此期间如果key的值如果发生的改变，刚不能为key设定值
     * 可以重新取得Key的值。
     * @param unknown $key
     */
    public function watch($key) {
        $this->connect();
        return $this->q->watch($key);
    }

    /**
     * 取消当前链接对所有key的watch
     *  EXEC 命令或 DISCARD 命令先被执行了的话，那么就不需要再执行 UNWATCH 了
     */
    public function unwatch() {
        $this->connect();
        return $this->q->unwatch();
    }

    /**
     * 开启一个事务
     * 事务的调用有两种模式Redis::MULTI和Redis::PIPELINE，
     * 默认是Redis::MULTI模式，
     * Redis::PIPELINE管道模式速度更快，但没有任何保证原子性有可能造成数据的丢失
     */
    public function multi($type = \Redis::MULTI) {
        $this->connect();
        return $this->q->multi($type);
    }

    /**
     * 执行一个事务
     * 收到 EXEC 命令后进入事务执行，事务中任意命令执行失败，其余的命令依然被执行
     */
    public function exec() {
        $this->connect();
        return $this->q->exec();
    }

    /**
     * 回滚一个事务
     */
    public function discard() {
        $this->connect();
        return $this->q->discard();
    }

}

?>